Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Icons #35

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Icons #35

wants to merge 3 commits into from

Conversation

SiyaTM
Copy link

@SiyaTM SiyaTM commented Mar 1, 2024

Task 2: Modify an Existing React/Redux Frontend

Aim
To support icons, I extended our existing React/Redux frontend written in TypeScript.

Software languages
modify the Goal model using TypeScript, integrate an emoji picker and lastly, extend the existing React components and Redux store to enable users to add and change icons

Typescript: Modification of the Goal model. By adding an emoji picker.
React- Extension of the React components.
Redux: The Redux store facility is used to enable users to add and change icons.

Result
GoalManager.tsx: Changes are made to the file.

Steps

  1. Update the client’s goal model
    File: types.ts
// types.ts

export interface Goal {
  // ...

  icon: string | null
}

Description:
Add an optional icon field of string type

  1. Display the icon on the goal card
    File: GoalCard.tsx
// GoalCard.tsx

const Icon = styled.h1`
  font-size: 5.5rem;
`

export default function GoalCard(props: Props) {
  // ...

  return (
    <Container key={goal.id} onClick={onClick}>
      {/* ... */}

      <Icon>{goal.icon}</Icon>
    </Container>
  )
}

Description:
In GoalCard.tsx, I've styled an element for the icon and integrated it into the GoalCard component. Now, each card displays its respective icon. This enhances visual consistency and improves user experience. Let me know if you need further details or have any feedback.

  1. Implement an emoji picker
  • Install emoji-mart at v3.0.1
    npm install [email protected]

  • Creation of a reusable wrapper. It uses mode from Redux themeSlice. Additionally it takes an onClick event handler with params: (emoji: BaseEmoji, event: React.MouseEvent) => void

File: EmojiPicker.tsx

// EmojiPicker.tsx
import { BaseEmoji, Picker } from 'emoji-mart'
import 'emoji-mart/css/emoji-mart.css'
import { useAppSelector } from '../../store/hooks'
import { selectMode } from '../../store/themeSlice'

type Props = { onClick: (emoji: BaseEmoji, event: React.MouseEvent) => void }

export default function EmojiPicker(props: Props) {
  const theme = useAppSelector(selectMode)

  return (
    <Picker
      theme={theme}
      showPreview={false}
      showSkinTones={false}
      onClick={props.onClick}
      color="primary"
    />
  )
}

Description:
The updated EmojiPicker component now integrates theme selection from the Redux store. Removed preview and skin tone options for simplicity. The component now renders a picker with the selected theme and emits clicked emojis via the provided callback. Styles imported from emoji-mart.css for consistent UI.

  • Display the emoji picker based on useState hook
    File: GoalManager.tsx
// GoalManager.tsx

type EmojiPickerContainerProps = { isOpen: boolean; hasIcon: boolean }

const EmojiPickerContainer = styled.div<EmojiPickerContainerProps>`
  display: ${(props) => (props.isOpen ? 'flex' : 'none')};
  position: absolute;
  top: ${(props) => (props.hasIcon ? '10rem' : '2rem')};
  left: 0;
`

export function GoalManager(props: Props) {
  const [emojiPickerIsOpen, setEmojiPickerIsOpen] = useState(false)

  const hasIcon = () => icon != null

  const pickEmojiOnClick = (emoji: BaseEmoji, event: MouseEvent) => {
    // TODO(TASK-2) Stop event propogation
    // TODO(TASK-2) Set icon locally
    // TODO(TASK-2) Close emoji picker
    // TODO(TASK-2) Create updated goal locally
    // TODO(TASK-2) Update Redux store
    // TODO(TASK-3) Update database
  }

  return (
    {/* ... */}

    <EmojiPickerContainer
      isOpen={emojiPickerIsOpen}
      hasIcon={hasIcon()}
      onClick={(event) => event.stopPropagation()}
    >
      <EmojiPicker onClick={pickEmojiOnClick} />
    </EmojiPickerContainer>

    {/* ... */}
  )
}

Description:
Team, in GoalManager.tsx, I've implemented an emoji picker feature. It appears based on a condition and adjusts its position accordingly. On selection, tasks for handling event propagation, local state updates, and Redux store updates are outlined. Further database integration is planned. Feedback is welcome.

  • Implement the pickEmojiOnClick event handler:
    File: GoalManager.tsx
// GoalManager.tsx
const pickEmojiOnClick = (emoji: BaseEmoji, event: MouseEvent) => {
  event.stopPropagation()

  setIcon(emoji.native)
  setEmojiPickerIsOpen(false)

  const updatedGoal: Goal = {
    ...props.goal,
    icon: emoji.native ?? props.goal.icon,
    name: name ?? props.goal.name,
    targetDate: targetDate ?? props.goal.targetDate,
    targetAmount: targetAmount ?? props.goal.targetAmount,
  }

  dispatch(updateGoalRedux(updatedGoal))

  // TODO(TASK-3) Update database
}

Description:
Team, in the pickEmojiOnClick function of GoalManager.tsx, now on emoji selection, it updates the local state and dispatches Redux action for goal update. Further, database integration is planned. Feedback appreciated.

  1. Modify the Goal manager so users can add and change icons
  • Add an "Add icon" component
    File: GoalManager.tsx
// GoalManager.tsx

export function GoalManager(props: Props) {
  // ...

  const [icon, setIcon] = useState<string | null>(null)

  useEffect(() => {
    setIcon(props.goal.icon)
  }, [props.goal.id, props.goal.icon])

  const hasIcon = () => icon != null

  const addIconOnClick = (event: React.MouseEvent) => {
    event.stopPropagation()
    setEmojiPickerIsOpen(true)
  }

  return (
    {/* ... */}
    <AddIconButtonContainer hasIcon={hasIcon()}>
      <TransparentButton onClick={addIconOnClick}>
        <FontAwesomeIcon icon={faSmile} size="2x" />
        <AddIconButtonText>Add icon</AddIconButtonText>
      </TransparentButton>
    </AddIconButtonContainer>
    {/* ... */}
  )
}

Description:
Team, in GoalManager.tsx, I've added an "Add icon" button. It triggers an emoji picker to select icons for goals. The icon state now updates dynamically based on goal changes, improving user interaction. Feedback is welcome.

  • Add an "Icon" component that:

File: GoalManager.tsx

//GoalManager.tsx

type GoalIconContainerProps = { shouldShow: boolean }

const GoalIconContainer = styled.div<GoalIconContainerProps>`
  display: ${(props) => (props.shouldShow ? 'flex' : 'none')};
`

export function GoalManager(props: Props) {
  // ...

  const hasIcon = () => icon != null

  const goal = useAppSelector(selectGoalsMap)[props.goal.id]

  return (
    {/* ... */}
    <GoalIconContainer shouldShow={hasIcon()}>
      <GoalIcon icon={goal.icon} onClick={addIconOnClick} />
    </GoalIconContainer>
    {/* ... */}
  )
}

Description:
In GoalManager.tsx, I've introduced a GoalIconContainer styled component that displays a goal's icon when available. It enhances goal visualization and user experience. Feedback is appreciated.

File: GoalIcon.tsx

// GoalIcon.tsx

const Icon = styled.h1`
  font-size: 6rem;
  cursor: pointer;
`

export default function GoalIcon(props: Props) {
  return (
    <TransparentButton onClick={props.onClick}>
      <Icon>{props.icon}</Icon>
    </TransparentButton>
  )
}

Description:
In GoalIcon.tsx, I've styled an icon component with a larger font size and cursor pointer. It's wrapped in a button for interaction. This enhances goal representation and encourages user engagement. Feedback welcomed.

Task 3: Modify the Client’s Requests

Aim
Wire together the backend and frontend.

Result
clientRequest.patch

Steps

  1. Add PUT Request to Lib
  • Add PUT request to update Goal

File: lib.ts

// lib.ts

export async function updateGoal(goalId: string, updatedGoal: Goal): Promise<boolean> {
  try {
    await axios.put(`${API_ROOT}/api/Goal/${goalId}`, updatedGoal)
    return true
  } catch (error: any) {
    return false
  }
}

Description:
In lib.ts, I've implemented an async function updateGoal to update goals via API. It utilizes axios to send a PUT request to the specified endpoint with the updated goal object. Returns true on success and false on failure. Feedback appreciated.

  1. Finish Implementing pickEmojiOnClick Event Handler
  • Import updateGoal PUT request
  • Call updateGoal on click

File: GoalManager.tsx

// GoalManager.tsx

import { updateGoal as updateGoalApi } from '../../../api/lib'
// ...

export function GoalManager(props: Props) {
  // ...

  const pickEmojiOnClick = () => (emoji: BaseEmoji, event: MouseEvent) => {
    // ...

    const updatedGoal: Goal = {
      ...props.goal,
      icon: emoji.native ?? props.goal.icon,
      name: name ?? props.goal.name,
      targetDate: targetDate ?? props.goal.targetDate,
      targetAmount: targetAmount ?? props.goal.targetAmount,
    }

    updateGoalApi(props.goal.id, updatedGoal)
  }
}

Description:
In GoalManager.tsx, I've integrated updateGoalApi from our library to update goals asynchronously on emoji selection. It sends updated goal data to the backend API. Enhances goal management functionality. Feedback is appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant